package main;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import data.Bird;
import data.Sighting;


public class FileHandler {


	private static int FINE = 0 ;
	private static int ERROR = 1 ; 
	private String directory ; 	
	private File birdfile ;
	private File sightingsfile;
	private Document birdfileDocument ; 
	private Document sightingsDocument ; 
	SecurityManager securityManager ; 
	public FileHandler(String dir) throws IOException
	{
		this.directory = dir ; 
		String separator = File.separator;
		//System.setSecurityManager(new SecurityManager());
		//securityManager = System.getSecurityManager();
		
		try
		{
			File directoryFile = new File(directory);
			birdfile = new File(directory+separator+"bird.xml");
			sightingsfile = new File(directory+separator+"sightings.xml");		

			try
			{
				//AccessController.checkPermission(new FilePermission(directory,"read,write"));
				
				if(directoryFile.exists()==false)
				{
					if(!directoryFile.mkdir())
						directoryFile.mkdirs();
				}

			}

			catch(SecurityException s)
			{
				System.out.println("Permission to write to the specified directory not allowed");
				System.exit(-1);
			}
			catch(Exception e)
			{
				System.out.println("Error creating the specified directory");
				e.printStackTrace();
				System.exit(-1);
			}
			if(!birdfile.exists())
			{
				birdfile.createNewFile();
			}
			if(!sightingsfile.exists())
			{
				sightingsfile.createNewFile();
			}
		}
		catch(FileNotFoundException e)
		{

			System.out.println("File Not found");
			System.exit(-1);
		}

		birdfileDocument = getDocument(birdfile);



		sightingsDocument = getDocument(sightingsfile);


	}

	private Document getDocument(File file) throws IOException
	{
		DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		try {
			builder = fact.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Document doc;
		try {
			doc = builder.parse(file);
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			if(file.getName().equals("bird.xml"))
			{
				doc = builder.newDocument();
				Element birds = doc.createElement("birds");
				doc.appendChild(birds);
			}
			else
			{

				doc = builder.newDocument();
				//	e.printStackTrace();
				Element sightings = doc.createElement("sightings");
				doc.appendChild(sightings);

			}
		}
		return doc;
	}
	public File getBirdfile() {
		return birdfile;
	}

	public File getSightingsfile() {
		return sightingsfile;
	}

	public Document getBirdfileDocument() {
		return birdfileDocument;
	}

	public Document getSightingsfileDocument() {
		return sightingsDocument;
	}


	public Bird getBird(String name)
	{
		//Document birdDocument = getBirdfileDocument();
		NodeList birds = birdfileDocument.getElementsByTagName("bird");

		int len = birds.getLength() ; 
		if(birds != null && len > 0) {
			for(int j = 0 ; j < len;j++) {
				Element current = (Element) birds.item(j);
				if(current.getElementsByTagName("name").item(0).getTextContent().toString().equalsIgnoreCase(name))
				{
					Bird bird = new Bird(name,current.getElementsByTagName("color").item(0).getTextContent().toString(),Integer.parseInt(current.getElementsByTagName("weight").item(0).getTextContent().toString()),Integer.parseInt(current.getElementsByTagName("height").item(0).getTextContent().toString()));
					return bird ; 
				}
			}

		}

		return null ; 
	}

	public synchronized int addNewSighting(String birdName , String date , String location)
	{
		if(this.getBird(birdName)!=null)
		{
			NodeList incidents = sightingsDocument.getElementsByTagName("incident");

			int len = incidents.getLength() ; 

			for(int i = 0 ; i < len ; i++)
			{
				Element current = (Element) incidents.item(i);

				//	System.out.println(current.getElementsByTagName("bird").item(0).getTextContent().trim());
				if(current.getElementsByTagName("bird").item(0).getTextContent().toString().trim().equalsIgnoreCase(birdName))
				{
					NodeList sightings = current.getElementsByTagName("sighting");

					Element newSighting = sightingsDocument.createElement("sighting");
					Element dateElement = sightingsDocument.createElement("time");

					Element locElement = sightingsDocument.createElement("location");

					locElement.setTextContent(location);
					dateElement.setTextContent(date);

					newSighting.appendChild(locElement);
					newSighting.appendChild(dateElement);

					current.appendChild(newSighting);

					//		this.writeXmlFile(sightingsDocument, sightingsfile);
					return FINE;
				}
			}

			return ERROR;

		}

		else
		{
			System.out.println("Bird not found");
			return ERROR;
		}

	}

	/***
	 * 
	 * @param name
	 * @param color
	 * @param weight
	 * @param height
	 * @return
	 */
	public synchronized int addNewBird(String name,String color , int weight , int height){

		if(this.getBird(name)==null)
		{

			//This code is used to add the appropriate entry to the birds.xml file
			//	NodeList birds = birdfileDocument.getElementsByTagName("birds");

			Element newElement = birdfileDocument.createElement("bird");
			birdfileDocument.getFirstChild().appendChild(newElement);
			//			birdfileDocument.appendChild(newElement);
			Element nameElement = birdfileDocument.createElement("name");
			Element colorElement = birdfileDocument.createElement("color");
			Element weightElement = birdfileDocument.createElement("weight");
			Element heightElement = birdfileDocument.createElement("height");

			nameElement.setTextContent(name);
			colorElement.setTextContent(color);
			weightElement.setTextContent(weight+"");
			heightElement.setTextContent(height+"");

			newElement.appendChild(nameElement);
			newElement.appendChild(colorElement);
			newElement.appendChild(weightElement);
			newElement.appendChild(heightElement);


			//This code will add the entry to the sightings.xml file

			Element newIncident = sightingsDocument.createElement("incident");
			sightingsDocument.getFirstChild().appendChild(newIncident);

			Element birdElement = sightingsDocument.createElement("bird");
			birdElement.setTextContent(name);
			newIncident.appendChild(birdElement);

			//	this.writeXmlFile(birdfileDocument, birdfile);
			//	this.writeXmlFile(sightingsDocument, sightingsfile);

			return FINE;
		}


		else 
		{
			return ERROR ; 
		}
	}


	public synchronized int removeBird(String name)
	{
		int flag = 1 ; 

		NodeList birds = birdfileDocument.getElementsByTagName("bird");

		int len = birds.getLength() ; 
		if(birds != null && len > 0) {
			for(int j = 0 ; j < len;j++) {
				Element current = (Element) birds.item(j);
				if(current.getElementsByTagName("name").item(0).getTextContent().toString().equalsIgnoreCase(name))
				{
					current.getParentNode().removeChild(current);
					flag =0 ; 
					break;
				}
			}
			return ERROR ; 
		}

		NodeList incidents = sightingsDocument.getElementsByTagName("incident");

		int len1 = incidents.getLength() ; 

		for(int i = 0 ; i < len1 ; i++)
		{
			Element currentIncident = (Element) incidents.item(i);

			//	System.out.println(current.getElementsByTagName("bird").item(0).getTextContent().trim());
			if(currentIncident.getElementsByTagName("bird").item(0).getTextContent().toString().trim().equalsIgnoreCase(name))
			{
				currentIncident.getParentNode().removeChild(currentIncident);
				break;
			}
		}
		return FINE;
	}

	public List<Sighting> ListSightings(String name,String startDate , String endDate)
	{

		if(this.getBird(name)!=null)
		{
			ArrayList sightingsList = new ArrayList<Sighting>();
			NodeList incidents = sightingsDocument.getElementsByTagName("incident");

			int len = incidents.getLength() ; 

			for(int i = 0 ; i < len ; i++)
			{
				Element current = (Element) incidents.item(i);

				//	System.out.println(current.getElementsByTagName("bird").item(0).getTextContent().trim());
				if(current.getElementsByTagName("bird").item(0).getTextContent().toString().trim().equalsIgnoreCase(name))
				{
					NodeList sightings = current.getElementsByTagName("sighting");
					SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm");

					int sightingsLen = sightings.getLength(); 

					for(int j = 0 ; j < sightingsLen ; j++)
					{
						Element currentSighting = (Element) sightings.item(j);

						String dateString = currentSighting.getElementsByTagName("time").item(0).getTextContent();
						try {
							Date date = sdf.parse(dateString);
							String locationString = currentSighting.getElementsByTagName("location").item(0).getTextContent();

							Date sDate = sdf.parse(startDate);
							Date eDate = sdf.parse(endDate);

							if((date.after(sDate)|| date.equals(sDate)) && (date.before(eDate))|| date.equals(eDate))
							{
								Sighting newSighting = new Sighting(locationString,date);
								sightingsList.add(newSighting);
							}
						} catch (ParseException e) {
							// TODO Auto-generated catch block
							System.out.println("Invalid Date "); 
							e.printStackTrace();
						}
					}

					Collections.sort(sightingsList);
					return sightingsList ; 
				}
			}
			return null ; 
		}
		else
		{
			System.out.println("Bird Not Found"); 

			return null ; 
		}
	}

	public List<Bird> ListBirds()
	{
		NodeList birds = birdfileDocument.getElementsByTagName("bird");
		ArrayList<Bird> birdList = new ArrayList<Bird>();
		int len = birds.getLength() ; 
		if(birds != null && len > 0) {
			for(int j = 0 ; j < len;j++) {
				Element current = (Element) birds.item(j);
				Bird bird = new Bird(current.getElementsByTagName("name").item(0).getTextContent(),current.getElementsByTagName("color").item(0).getTextContent().toString(),Integer.parseInt(current.getElementsByTagName("weight").item(0).getTextContent().toString()),Integer.parseInt(current.getElementsByTagName("height").item(0).getTextContent().toString()));
				birdList.add(bird);
			}

		}
		Collections.sort(birdList);
		return birdList ; 
	}


	private  static void writeXmlFile(Document doc , File file) {
		try {
			// Prepare the DOM document for writing
			Source source = new DOMSource(doc);

			// Prepare the output file
			//            File file = new File(filename);
			Result result = new StreamResult(file);

			// Write the DOM document to the file
			Transformer xformer = TransformerFactory.newInstance().newTransformer();
			xformer.transform(source, result);
		} catch (TransformerConfigurationException e) {
		} catch (TransformerException e) {
		}
	}


	public synchronized void commit()
	{
		this.writeXmlFile(birdfileDocument, birdfile);
		this.writeXmlFile(sightingsDocument, sightingsfile);

	}

/***
	public static void main (String args[])
	{
		//		String dir = System.getProperty("user.dir");
		String dir = "C:\\Users\\rushabh\\Desktop\\test";
		try {
			FileHandler test = new FileHandler(dir);
			//						test.getBird("bird1");
			//					test.addNewBird("bird1", "asdsa", 10, 12);
			//			test.addNewSighting("bird2", "1/1/08", "Santa Clara");
			//			test.addNewSighting("bird2", "2/2/07", "Bombay");
			//			test.addNewSighting("bird2", "3/4/08", "Bombay");
			//			test.addNewSighting("bird2", "4/3/06", "Bombay");


			//			List<Sighting> sightings = test.ListSightings("bird2");
			//			
			//			for(Sighting si:sightings)
			//			{
			//				System.out.println(si.getLocation() + "::" + si.getDateTime().toString());
			//			}
			//			test.removeBird("bird1");

			List<Bird> birds = test.ListBirds();

			for(Bird currentBird:birds)
			{
				System.out.println(currentBird.getName());
			}

		}	catch (IOException e) {

			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	} 
**/
	
}
